package cn.snmp.mutual.org.opennms.protocols.snmp;

import cn.snmp.mutual.org.opennms.protocols.snmp.asn1.AsnEncoder;
import cn.snmp.mutual.org.opennms.protocols.snmp.asn1.AsnEncodingException;
import java.io.*;
import java.net.*;

public final class SnmpTrapSession {
    public static final int ERROR_EXCEPTION = -1;
    public static final int ERROR_INVALID_PDU = -2;
    public static final int DEFAULT_PORT = 162;
    private int m_port;
    private SnmpPortal m_portal;
    private AsnEncoder m_encoder;
    private SnmpTrapHandler m_handler;
    private boolean m_threadException;
    private Throwable m_why;

    private SnmpTrapSession() throws UnsupportedOperationException {
        throw new UnsupportedOperationException("Illegal constructor call");
    }

    public SnmpTrapSession(final SnmpTrapHandler handler) throws SocketException {
        this.m_port = 162;
        this.m_encoder = new SnmpParameters().getEncoder();
        this.m_threadException = false;
        this.m_why = null;
        this.m_handler = handler;
        this.m_portal = new SnmpPortal(new TrapHandler(this), this.m_encoder, this.m_port);
    }

    public SnmpTrapSession(final SnmpTrapHandler handler, final int port) throws SocketException {
        this.m_port = port;
        this.m_encoder = new SnmpParameters().getEncoder();
        this.m_handler = handler;
        this.m_portal = new SnmpPortal(new TrapHandler(this), this.m_encoder, this.m_port);
        this.m_threadException = false;
        this.m_why = null;
    }

    public SnmpTrapHandler getHandler() {
        return this.m_handler;
    }

    public void setHandler(final SnmpTrapHandler hdl) {
        this.m_handler = hdl;
    }

    public void setAsnEncoder(final AsnEncoder encoder) {
        this.m_encoder = encoder;
        this.m_portal.setAsnEncoder(encoder);
    }

    public AsnEncoder getAsnEncoder() {
        return this.m_encoder;
    }

    public boolean isClosed() {
        return this.m_portal.isClosed();
    }

    public void close() {
        if (this.m_portal.isClosed()) {
            throw new IllegalStateException("Illegal operation, the session is already closed");
        }
        this.m_portal.close();
    }

    public void raise() throws Throwable {
        if (this.m_threadException) {
            throw this.m_why;
        }
    }

    public void send(final SnmpPeer peer, final SnmpPduTrap trap) throws SnmpPduEncodingException, AsnEncodingException, IOException {
        if (this.m_portal.isClosed()) {
            throw new IllegalStateException("Illegal operation, the session has been closed");
        }
        final SnmpParameters parms = peer.getParameters();
        if (parms.getVersion() != 0) {
            throw new SnmpPduEncodingException("Cannot send pdu, invalid SNMP version");
        }
        final AsnEncoder encoder = parms.getEncoder();
        final int begin = 0;
        int offset = 0;
        final byte[] buf = new byte[16384];
        final SnmpInt32 version = new SnmpInt32(parms.getVersion());
        offset = version.encodeASN(buf, offset, encoder);
        final SnmpOctetString community = new SnmpOctetString(parms.getReadCommunity().getBytes());
        offset = community.encodeASN(buf, offset, encoder);
        final int pivot;
        offset = (pivot = trap.encodeASN(buf, offset, encoder));
        offset = encoder.buildHeader(buf, offset, (byte) 48, pivot);
        SnmpUtil.rotate(buf, 0, pivot, offset);
        this.m_portal.send(peer, buf, offset);
    }

    public void send(final SnmpPeer peer, final SnmpPduPacket pdu) throws SnmpPduEncodingException, AsnEncodingException, IOException {
        if (this.m_portal.isClosed()) {
            throw new IllegalStateException("Illegal operation, the session has been closed");
        }
        final SnmpParameters parms = peer.getParameters();
        switch (pdu.getCommand()) {
            case 167: {
                if (parms.getVersion() < 1) {
                    throw new SnmpPduEncodingException("Cannot send pdu, invalid SNMP version");
                }
                final AsnEncoder encoder = parms.getEncoder();
                final int begin = 0;
                int offset = 0;
                final byte[] buf = new byte[16384];
                final SnmpInt32 version = new SnmpInt32(parms.getVersion());
                offset = version.encodeASN(buf, offset, encoder);
                final SnmpOctetString community = new SnmpOctetString(parms.getReadCommunity().getBytes());
                offset = community.encodeASN(buf, offset, encoder);
                final int pivot;
                offset = (pivot = pdu.encodeASN(buf, offset, encoder));
                offset = encoder.buildHeader(buf, offset, (byte) 48, pivot);
                SnmpUtil.rotate(buf, 0, pivot, offset);
                this.m_portal.send(peer, buf, offset);
            }
            default: {
                throw new SnmpPduEncodingException("Invalid pdu, not a trap");
            }
        }
    }

    private class TrapHandler implements SnmpPacketHandler {
        private SnmpTrapSession m_forWhom;

        public TrapHandler(final SnmpTrapSession sess) {
            this.m_forWhom = sess;
        }

        public void processSnmpMessage(final InetAddress agent, final int port, final SnmpInt32 version, final SnmpOctetString community, final int pduType, final SnmpPduPacket pdu) throws SnmpPduEncodingException {
            if (version.getValue() != 1 && pduType != 167) {
                return;
            }
            try {
                SnmpTrapSession.this.m_handler.snmpReceivedTrap(this.m_forWhom, agent, port, community, pdu);
            } catch (Exception ex) {
            }
        }

        public void processSnmpTrap(final InetAddress agent, final int port, final SnmpOctetString community, final SnmpPduTrap pdu) throws SnmpPduEncodingException {
            try {
                SnmpTrapSession.this.m_handler.snmpReceivedTrap(this.m_forWhom, agent, port, community, pdu);
            } catch (Exception ex) {
            }
        }

        public void processBadDatagram(final DatagramPacket p) {
        }

        public void processException(final Exception e) {
            try {
                SnmpTrapSession.this.m_handler.snmpTrapSessionError(this.m_forWhom, -1, e);
            } catch (Exception ex) {
            }
        }
    }
}
